import { ResultType } from '@xtail/result'
import { PouchDBConfOptionsType, PouchDBFindOptionsType, DB } from '../classes'
import { save, saveBatch } from './save'
import { find } from './find'
import { removeById, removeByIds, remove } from './remove'

export const SaveDocType_Name = 'SaveDocType'
export const SaveDocsType_Name = 'SaveDocsType'
export const FindDocsType_Name = 'FindDocsType'
export const RemoveDocByIdType_Name = 'RemoveDocByIdType'
export const RemoveDocsByIdsType_Name = 'RemoveDocsByIdsType'
export const RemoveDocsType_Name = 'RemoveDocsType'
export const crud_Name = 'crud'
export const CrudType_Name = 'CrudType'

export type SaveDocType = (doc: Record<string, any>) => Promise<ResultType>

export type SaveDocsType = (doc: Record<string, any>[]) => Promise<ResultType>

export type FindDocsType = (options?: PouchDBFindOptionsType) => Promise<ResultType>

export type RemoveDocByIdType = (id: string) => Promise<ResultType>

export type RemoveDocsByIdsType = (ids: string[]) => Promise<ResultType>

export type RemoveDocsType = (options?: PouchDBFindOptionsType) => Promise<ResultType>

/**
 * 根据数据库名称和数据库路径创建数据库实例对象，并生成该数据库文档 CRUD 方法
 *
 * @param {{dbName: string; dbPath?: string; dbOptions?: PouchDBConfOptionsType}} options 配置选项：
 * - dbName 数据库名称
 * - dbPath 数据库存放路径，即数据库存放在哪个目录下，默认为当前执行脚本所 在的目录 __dirname
 * - options 数据库配置选项，数据库底层存储引擎默认使用 leveldb
 * @returns 返回值 一个数组，该数组包含：
 * - 数据库实例
 * - 保存文档到数据库的方法
 * - 批量保存文档到数据库的方法
 * - 从数据库中查询文档的方法
 * - 根据 id 删除数据库中的文档的方法
 * - 根据 id 列表批量删除数据库中的文档的方法
 * - 根据条件批量删除数据库中的文档的方法
 */
export const crud = ({
  dbName,
  dbPath = __dirname,
  dbOptions = {}
}: {
  dbName: string
  dbPath?: string
  dbOptions?: PouchDBConfOptionsType
}): [
  DB,
  SaveDocType,
  SaveDocsType,
  FindDocsType,
  RemoveDocByIdType,
  RemoveDocsByIdsType,
  RemoveDocsType
] => {
  const db = new DB(dbName, dbPath, dbOptions)
  const saveDoc: SaveDocType = async doc => await save(db, doc)
  const saveDocs: SaveDocsType = async docs => await saveBatch(db, docs)
  const findDocs: FindDocsType = async options => await find(db, options)
  const removeDocById: RemoveDocByIdType = async id => await removeById(db, id)
  const removeDocsByIds: RemoveDocsByIdsType = async ids => await removeByIds(db, ids)
  const removeDocs: RemoveDocsType = async options => await remove(db, options)
  return [db, saveDoc, saveDocs, findDocs, removeDocById, removeDocsByIds, removeDocs]
}

export type CrudType = typeof crud
